package com.mask.sca.gateway.filter;

import com.alibaba.fastjson.JSONObject;

import com.mask.sca.core.response.ApiResponse;
import io.jsonwebtoken.*;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StringUtils;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import javax.security.sasl.AuthenticationException;
import java.nio.charset.StandardCharsets;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;

@Log4j2
@Component
public class AuthGlobalFilter implements GlobalFilter, Ordered {
    // 白名单路径（可配置化）
    private static final List<String> WHITE_LIST = Arrays.asList(
            "/auth/login", "/auth/register", "/v3/api-docs/**", "/swagger-ui/**", "/doc.html", "/auth/**", "/member/member/login", "/system/system/login",
            "/member/member/register"
    );
    private static final AntPathMatcher pathMatcher = new AntPathMatcher();

    @Value("${jwt.secret}")
    private String jwtSecret;

    @Value("${jwt.issuer}")
    private String jwtIssuer;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        String path = exchange.getRequest().getURI().getPath();
        // 白名单放行
        for (String pattern : WHITE_LIST) {
            if (pathMatcher.match(pattern, path)) {
                return chain.filter(exchange);
            }
        }

        // 获取Token
        String token = exchange.getRequest().getHeaders().getFirst("Authorization");
        if (!StringUtils.hasText(token) || !token.startsWith("Bearer ")) {
            return unauthorized(exchange, "未认证或Token无效", 203);
        } else {
            try {
                //TODO::token过期,黑名单,无效
                Claims claims = Jwts.parser().setSigningKey("OAuth2Constant.SIGN_KEY".getBytes(StandardCharsets.UTF_8)).parseClaimsJws(token.substring(7)).getBody();
                Map<String, Object> currentUserInfoMap = new HashMap<>();
                currentUserInfoMap.put("userId", String.valueOf(claims.get("userId")));
                currentUserInfoMap.put("userName", String.valueOf(claims.get("userName")));
                currentUserInfoMap.put("userType", String.valueOf(claims.get("userType")));
                Consumer<HttpHeaders> httpHeaders = httpHeader -> {
                    httpHeader.set("currentUserInfo", JSONObject.toJSONString(currentUserInfoMap));
                };
                ServerHttpRequest serverHttpRequest = exchange.getRequest().mutate().headers(httpHeaders).build();
                exchange.mutate().request(serverHttpRequest).build();
            } catch (ExpiredJwtException e) {
                log.warn("Token已过期: {}", e.getMessage());
                return unauthorized(exchange, "Token已过期", 203);
            } catch (UnsupportedJwtException | MalformedJwtException | SignatureException e) {
                log.error("无效Token: {}", e.getMessage());
                return unauthorized(exchange, "无效的Token", 203);
            } catch (IllegalArgumentException e) {
                log.error("Token解析错误: {}", e.getMessage());
                return unauthorized(exchange, e.getMessage(), 203);
            } catch (Exception e) {
                log.error("认证过程发生未知错误: {}", e.getMessage(), e);
                return unauthorized(exchange, "认证服务暂时不可用", 203);
            }
        }
        //解析token
        // 直接透传，不做JWT解析
        return chain.filter(exchange);
    }

    private Mono<Void> unauthorized(ServerWebExchange exchange, String msg, Integer code) {
//        String body = String.format("{\"code\":401,\"msg\":\"%s\"}", msg);
        String body = JSONObject.toJSONString(ApiResponse.fail(code, msg));
        exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
        exchange.getResponse().getHeaders().setContentType(MediaType.APPLICATION_JSON);
        return exchange.getResponse().writeWith(Mono.just(
                exchange.getResponse().bufferFactory().wrap(body.getBytes(StandardCharsets.UTF_8))
        ));
    }

    @Override
    public int getOrder() {
        return -100;
    }
} 